package com.fengye.lock.zk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fengye.lock.zk.domain.UserReg;
import com.fengye.lock.zk.dto.UserRegDTO;
import com.fengye.lock.zk.mapper.UserRegMapper;
import com.fengye.lock.zk.service.UserRegService;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author sky
 * @date 2021年06月15日 11:00 下午
 */
@Service
@Slf4j
public class UserRegServiceImpl extends ServiceImpl<UserRegMapper, UserReg> implements UserRegService {
    @Autowired
    private CuratorFramework client;

    private static final String pathPrefix = "/lock/";

    /**
     * 根据用户名查询用户
     * @param username 用户名
     */
    @Override
    public UserReg selectByUsername(String username) {
        QueryWrapper<UserReg> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name", username);
        UserReg userReg = this.baseMapper.selectOne(wrapper);
        return userReg;
    }

    @Override
    public void registerWithZkLock(UserRegDTO dto) throws Exception {
        // 创建 zookeeper 互斥锁组件实例
        // 需要将监控用的客户端实例、共享资源作为构造参数
        InterProcessMutex mutex = new InterProcessMutex(client, pathPrefix + dto.getUsername() + "-lock");

        try {
            // 采用互斥锁组件尝试获取分布式锁，其中尝试的最大时间为 10s
            // 根据实际情况，待定
            if (mutex.acquire(10L, TimeUnit.SECONDS)) {
                // TODO: 获取到锁，处理业务逻辑

                UserReg userReg = this.selectByUsername(dto.getUsername());
                if (userReg ==null) {
                    log.info("使用分布式锁--zookeeper实现：当前注册用户为：{}", dto);

                    UserReg reg = new UserReg();
                    reg.setUserName(dto.getUsername());
                    reg.setPassword(dto.getPassword());
                    reg.setCreateTime(new Date());
                    log.info("reg={}", reg);
                    this.save(reg);
                }else {
                    throw new Exception("用户名已存在");
                }


            }else{
                throw new RuntimeException("获取zookeeper分布式锁失败");
            }
        } catch (Exception e) {
            throw e;
        }finally {
            // TODO: 不管发生任何情况，在处理完核心业务逻辑之后，需要释放分布式锁
            mutex.release();
        }
    }
}
